import pages from '@/config/pages';
import webs from '@/config/webs';
import apicloudConfig from '@/config/apicloud';
import PathUtils from '@/lib/utils/PathUtils';
import EventEmitter from '../EventEmitter';
type PAGES = typeof pages;
type WEBS = typeof webs;

export { PAGES, WEBS };

export default class Apicloud {
    private static instance: Apicloud;
    public static getInstance() {
        if (!this.instance) {
            this.instance = new Apicloud();
        }
        return this.instance;
    }
    private mOpenDialogMethod = `__open_dialog_`;
    private mCloseDialogMethod = `__close_dialog_`;
    // 已经打开的弹窗名数组
    private mDialogFrms: { [name: string]: { callbackMethod: (data: any) => void, back: boolean } } = {};
    private mDialogStacks: string[] = [];


    private constructor() {

    }

    /**
     * 打开新窗口
     * @param name 窗口名 
     * @param config 配置
     */
    public async openWin<T extends keyof PAGES>(name: T, config: OpenWinParams = {}) {
        if (!await apicloudConfig.OPEN_WIN_INTERCEPTORS(name, config)) {
            return;
        }
        if (typeof config.name === 'undefined') {
            config.name = name;
        }
        config.url = pages[name];
        config.slidBackType = 'edge';

        api.openWin(config);
    }

    /**
     * 打开带头部的窗口
     * @param title 头部标题
     * @param name  窗口名
     * @param config 配置
     */
    public async openTabLayout<T extends keyof PAGES>(title: string, name: T, config: OpenTabLayoutParams = {}) {
        if (!await apicloudConfig.OPEN_WIN_INTERCEPTORS(name, config)) {
            return;
        }
        if (typeof config.name === 'undefined') {
            config.name = name;
        }
        config.title = title;
        config.url = pages[name];
        if (!config.navigationBar) {
            config.navigationBar = {
                background: apicloudConfig.HEADER_BG_COLOR,
                color: apicloudConfig.HEADER_COLOR,
            }
        }
        if (!config.navigationBar.leftButtons) {
            config.navigationBar.leftButtons = [];
        }
        config.navigationBar.height = apicloudConfig.HEADER_HEIGHT;
        if (apicloudConfig.HEADER_WEIGHT) {
            config.navigationBar.fontWeight = 'bold';
        }
        config.slidBackType = 'edge';

        const baclIcon = config.style === 'dark' ? apicloudConfig.HEADER_BACK_BUTON_LIGHT_ICON : apicloudConfig.HEADER_BACK_BUTON_DARK_ICON;
        config.navigationBar.leftButtons.push({
            iconPath: PathUtils.resolve(baclIcon),
        });
        api.openTabLayout(config);
    }


    /**
     * 打开子窗口
     * @param name 窗口名 
     * @param config 配置
     */
    public openFrm<T extends keyof PAGES>(name: T, config: OpenFrameParams = {}) {
        if (typeof config.name === 'undefined') {
            config.name = name;
        }
        config.url = pages[name];
        api.openFrame(config);
    }

    /**
     * 打开子窗口组
     * @param name  组名
     * @param frms  子窗口数组
     * @param config  组配置
     * @param callback  组子窗切换回调
     */
    public openFrmGroup<T extends keyof PAGES>(name: string, frms: Array<{ name: T, config?: OpenFrameParams, url?: string }>, config: FrmameGroupParams = {}, callback?: (ret: { name: string, index: number }, err: any) => void) {
        const frames = frms.map((item, index) => {
            return {
                name: `${name}_${index}`,
                url: item.url || pages[item.name],
                ...item.config,
            }
        });
        config.frames = frames;
        config.name = name;
        api.openFrameGroup(config, callback);
    }


    /**
     * 打开有和原生交互的H5页面
     * @param url 
     * @param config 
     */
    public openH5NavtiveUrl(url: string, config: OpenWinParams = {}) {
        if (typeof config.name === 'undefined') {
            config.name = 'h5_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
        }
        config.url = pages.app_h5_navtive;
        config.pageParam = {
            ...config,
            url,
        }
        config.slidBackType = 'edge';

        api.openWin(config);
    }

    /**
     * 打开有和原生交互的H5页面
     */
    public async openH5Navtive<T extends keyof WEBS>(name: T, config: OpenWinParams = {}) {
        if (!await apicloudConfig.OPEN_WIN_INTERCEPTORS(name, config)) {
            return;
        }
        if (typeof config.name === 'undefined') {
            config.name = name;
        }
        const url = webs[name];
        this.openH5NavtiveUrl(url, config);
    }

    /**
    * 打开有和原生交互的H5页面
    * @param url 
    * @param config 
    */
    public openH5NavtiveTitleUrl(url: string, config: OpenTabLayoutParams = {}) {
        if (typeof config.name === 'undefined') {
            config.name = 'h5_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
        }
        if (!config.navigationBar) {
            config.navigationBar = {
                background: apicloudConfig.HEADER_BG_COLOR,
                color: apicloudConfig.HEADER_COLOR,
            }
        }
        if (!config.navigationBar.leftButtons) {
            config.navigationBar.leftButtons = [];
        }
        config.navigationBar.height = apicloudConfig.HEADER_HEIGHT;
        const baclIcon = config.style === 'dark' ? apicloudConfig.HEADER_BACK_BUTON_LIGHT_ICON : apicloudConfig.HEADER_BACK_BUTON_DARK_ICON;
        config.navigationBar.leftButtons.push({
            iconPath: PathUtils.resolve(baclIcon),
        });
        const closeIcon = config.style === 'dark' ? apicloudConfig.HEADER_CLOSE_BUTON_LIGHT_ICON : apicloudConfig.HEADER_CLOSE_BUTON_DARK_ICON;
        config.navigationBar.leftButtons.push({
            iconPath: PathUtils.resolve(closeIcon),
        });
        config.url = pages.app_h5_navtive;
        const title = config.title;
        config.title = title || api.appName
        config.pageParam = {
            ...config,
            url,
            title
        }
        if (apicloudConfig.HEADER_WEIGHT) {
            config.navigationBar.fontWeight = 'bold';
        }
        config.slidBackType = 'edge';
        api.openTabLayout(config);
    }


    /**
     * 打开带头部和原生交互的H5页面
     * 
     * @param name 
     * @param config 
     */
    public async openH5NavtiveTitle<T extends keyof WEBS>(name: T, config: OpenTabLayoutParams = {}) {
        if (!await apicloudConfig.OPEN_WIN_INTERCEPTORS(name, config)) {
            return;
        }
        if (typeof config.name === 'undefined') {
            config.name = name;
        }
        const url = webs[name];
        this.openH5NavtiveTitleUrl(url, config);
    }




    /**
     * 关闭窗口
     * @param name 窗口名
     * @param config  配置
     */
    public closeWin<T extends keyof PAGES>(name?: T, config: CloaseWinParams = {}) {
        if (name) {
            config.name = name;
        }
        api.closeWin(config);
    }

    /**
    * 关闭到某个窗口
    * @param name 窗口名
    * @param config  配置
    */
    public closeToWin<T extends keyof PAGES>(name?: T | 'root', config: CloaseWinParams = {}) {
        config.name = name;
        api.closeToWin(config);
    }

    /**
     * 设置窗口参数
     * @param params 
     */
    public setWinAttr(params: OpenWinParams) {
        api.setWinAttr(params);
    }

    /**
     * 关闭子窗口
     * @param name 子窗口名
     * @param config  配置
     */
    public closeFrm<T extends keyof PAGES>(name?: T, config: CloseFrameParams = {}) {
        config.name = name;
        api.closeFrame(config);
    }

    /**
     * 设置子窗口参数
     * @param params 
     */
    public setFrmAttr(params: OpenFrameParams) {
        api.setFrameAttr(params);
    }
    /**
     * 设置子窗口组显示第几个
     * @param params 
     */
    public setFrmGroupIndex(params: { name: string, index: number, scroll?: boolean, reload?: boolean }) {
        api.setFrameGroupIndex(params);
    }
    /**
     * 全局提示信息
     * @param msg 提示信息
     * @param duration 时常
     */
    public toast(msg: string, duration: number = 1500) {
        api.toast({
            msg,
            global: api.systemType !== 'ios',
            location: "middle",
            duration
        });
    }

    /**
     * 打开一个弹窗
     * @param name 弹窗名
     * @param data 附加数据
     * @param config 配置，可选
     */
    public openDialogFrm<Name extends keyof typeof pages>(name: Name, data?: { [key: string]: any }, config: { back?: false, config?: OpenFrameParams } = {}) {
        return this.openDialogFrmByUrl(pages[name], data, {
            back: config.back,
            config: {
                ...config.config,
                name
            }

        });
    }

    /**
     * 根据url打开一个弹窗
     * @param url 
     * @param data 
     * @param config 
     */
    public openDialogFrmByUrl(url: string, data?: { [key: string]: any }, config: { back?: false, config?: OpenFrameParams } = {}) {
        return new Promise<{ [key: string]: any, closeType?: 'keyback' }>((res) => {
            if (!config) {
                config = {}
            }
            if (!config.config) {
                config.config = {}
            }
            if (!config.config.name) {
                config.config.name = 'dialog_frm_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
            }
            const name = config.config.name;
            if (api.frameName) {
                // frm下通过win打开
                const frmCallbackMethod = `_${name}_${Date.now()}`;
                Object.defineProperty(window, frmCallbackMethod, {
                    value: (data: any) => {
                        res(data);
                    }
                });
                api.execScript({
                    name: api.winName,
                    script: `${this.mOpenDialogMethod}('${url}',${JSON.stringify(data)},${JSON.stringify(config)},'${api.frameName}','${frmCallbackMethod}');`
                });
                return;
            }
            this.mDialogStacks.push(name);
            this.mDialogFrms[name] = {
                back: config.back !== false,
                callbackMethod: (data) => {
                    res(data);
                }
            }
            this.setWinAttr({
                slidBackEnabled: false
            });

            api.openFrame({
                ...config.config,
                name,
                url,
                bgColor: 'rgba(0,0,0,0)',
                pageParam: data
            });
        });
    }



    /**
     * 关闭一个弹窗
     * @param name
     * @param data 
     */
    public closeDialogFrm<Name extends keyof typeof pages>(name?: Name, data?: { [key: string]: any }) {
        if (api.frameName) {
            // frm下通过win关闭
            api.execScript({
                name: api.winName,
                script: `${this.mCloseDialogMethod}(${typeof name === 'undefined' ? name : '"' + name + '"'},${JSON.stringify(data)});`
            });
            return;
        }
        const dName = name || this.mDialogStacks[this.mDialogStacks.length - 1];
        const index = this.mDialogStacks.indexOf(dName);
        if (index === -1) {
            if (this.mDialogStacks.length === 0) {
                this.closeWin();
            }
            return;
        }
        const dialog = this.mDialogFrms[dName];
        dialog.callbackMethod(data || {});
        delete this.mDialogFrms[dName];
        this.mDialogStacks.splice(index);
        if (this.mDialogStacks.length === 0) {
            this.setWinAttr({
                slidBackEnabled: true
            });
        }
        this.closeFrm(dName as any);
    }

    /**
     * 初始化弹窗逻辑
     * 外部,逻辑代码禁止调用
     */
    private initDialog() {
        if (api.frameName) {
            return;
        }
        let lastBackTime = 0;
        EventEmitter.onSystem({
            name: 'keyback'
        }, () => {
            const stacks = this.mDialogStacks;
            if (stacks.length === 0) {
                if (EventEmitter.getListener('keyback') > 1) {
                    return;
                }
                if (api.winName === 'root') {
                    const isQ = location.href.indexOf('?') > -1;
                    const curBackTime = Date.now();
                    if (!isQ && curBackTime - lastBackTime > 2000) {
                        lastBackTime = curBackTime;
                        this.toast('再按一次退出');
                    } else {
                        api.closeWidget({
                            silent: true
                        });
                    }
                } else {

                    this.closeWin();
                }
                return;
            }
            const dialogName = stacks[stacks.length - 1] as any;
            const dialog = this.mDialogFrms[dialogName];
            if (!dialog.back) {
                return false;
            }
            this.closeDialogFrm(dialogName, {
                closeType: 'keyback'
            });
            return false;
        })

        Object.defineProperty(window, this.mOpenDialogMethod, {
            value: (url: string, data: { [key: string]: any }, config: { back?: false, config?: OpenFrameParams } = {}, frameName: string, callbackMethod: string) => {
                this.createDialogFrm(url, data, config, frameName, callbackMethod);
            }
        });
        Object.defineProperty(window, this.mCloseDialogMethod, {
            value: <Name extends keyof typeof pages>(name: Name, data: { [key: string]: any }) => {
                this.closeDialogFrm(name, data);
            }
        })
    }
    /**
     * 创建一个弹窗
     * @param name 
     * @param data 
     * @param frameName 
     * @param callbackMethod 
     */
    private createDialogFrm(url: string, data: { [key: string]: any } = {}, config: { back?: false, config?: OpenFrameParams } = {}, frameName: string, callbackMethod: string) {
        if (!config) {
            config = {}
        }
        if (!config.config) {
            config.config = {}
        }
        if (!config.config.name) {
            config.config.name = 'dialog_frm_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
        }
        const name = config.config.name;
        this.mDialogStacks.push(name);
        this.mDialogFrms[name] = {
            back: config.back !== false,
            callbackMethod: (data) => {
                if (frameName) {
                    api.execScript({
                        name: api.winName,
                        frameName,
                        script: `${callbackMethod}(${data ? JSON.stringify(data) : ''});`
                    });
                }
            }
        }
        this.setWinAttr({
            slidBackEnabled: false
        });
        api.openFrame({
            ...config.config,
            name,
            url,
            bgColor: 'rgba(0,0,0,0)',
            pageParam: data
        });
    }

}

